<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>RTCPeerConnection 连接测试</title>
</head>
<body>
<div class="app">
  <input type="button" title="开始" value="开始" v-on:click="start"/>
  <input type="button" title="呼叫" value="呼叫" v-on:click="call"/>
  <input type="button" title="挂断" value="挂断" v-on:click="stop"/>
  <input type="button" value="同步" v-on:click="canPlay"/>
  <hr>

  <span>当前使用视频设备：{[videoDeviceName]}</span>
  <br> <br>
  <span>当前使用音频设备：{[audioDeviceName]}</span>
  <hr>

  {{/*    本地视频*/}}
  <video id="localVideo" class="localVideo" height="240px" width="280px" playsinline autoplay muted></video>
  {{/*    远端视频*/}}
  <video id="remoteVideo" class="remoteVideo" height="240px" width="280px" playsinline autoplay muted></video>
  {{/*    本地mp4文件*/}}

  <br> <br>
  <hr>
  <span>测试本地mp4文件</span>

  <br>

  <br>
  <video id="myVideo" class="myVideo" autoplay="autoplay" width="400" height="200" controls loop muted
         v-on:oncanplay="canPlay">
    <source src="/static/file/capture.mp4" type="video/mp4">
  </video>

</div>
</body>
<script src="/static/js/Vue.2.5.3.js"></script>
<script type="text/javascript">
  navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
  let vm = new Vue({
    el: ".app",
    delimiters: ['{[', ']}'],
    data: {
      // 测试我的视频
      myVideo: null,
      // 本地视频
      localVideo: null,
      // 本地视频流
      localStream: null,
      // 远端视频流
      remoteVideo: null,
      isOpen: false,
      videoDeviceName: "",
      audioDeviceName: "",
      // ICE service地址
      configuration: {
        "iceServers": [{"url": "stun:stun.1.google.com:19302"}]
      },
      // peerConnA 本地对象
      peerConnA: null,
      // peerConnB 远程对象
      peerConnB: null,
      // 本地视频轨道
      videoTracks: [],
      // 本地音频轨道
      audioTrack: []
    },
    methods: {
      canPlay: function () {
        alert("zheli")
        let fps = 0;
        // 捕捉
        if (this.myVideo.captureStream) {
          this.localStream = this.myVideo.captureStream(fps)
        } else if (this.capture.mozCaptureStream) {
          this.localStream = this.myVideo.mozCaptureStream(fps)
        } else {
          alert("不支持 captureStream")
        }

      },
      stop: function () {
        let that = this
        that.peerConnB.close()
        that.peerConnA.close()
        that.peerConnA = null
        that.peerConnB = null
        console.log("关闭会话")
      }
      ,
      start: async function () {
        let that = this;
        if (that.isOpen) {
          return
        }
        try {
          that.localStream = await navigator.mediaDevices.getUserMedia({audio: true, video: true})
          that.isOpen = true
          that.localVideo.srcObject = that.localStream
          that.remoteVideo.srcObject = that.localStream
          console.log("获取本地流成功", that.localStream)
          // 获取设备轨道
          that.videoTracks = that.localStream.getVideoTracks()
          that.audioTrack = that.localStream.getAudioTracks()
          if (that.videoTracks.length > 0) {
            that.videoDeviceName = that.videoTracks[0].label
          }
          if (that.audioTrack.length > 0) {
            that.audioDeviceName = that.audioTrack[0].label
          }

        } catch (e) {
          console.log("getUserMedia 错误" + e)
        }
      }
      ,
      call: async function () {
        let that = this;
        console.log("开始呼叫")

        //  监听返回icecandidate 信息
        that.peerConnA = new RTCPeerConnection(that.configuration)
        that.peerConnA.addEventListener("icecandidate", that.onIceCandidateA)
        that.peerConnB = new RTCPeerConnection(that.configuration)
        that.peerConnB.addEventListener("icecandidate", that.onIceCandidateB)
        // 监听ICE状态变化
        that.peerConnA.addEventListener("iceconnectionstatechange", that.onIceStateChangeA)
        that.peerConnB.addEventListener("iceconnectionstatechange", that.onIceStateChangeB)

        // 监听track,获取远端视频流视频
        that.peerConnB.addEventListener("track", that.getRemoteStream)
        // 将本地流加入本地连接
        that.localStream.getTracks().forEach((track) => {
          that.peerConnA.addTrack(track, that.localStream)
        })


        // 创建通话offer
        try {
          console.log("peerConnA 创建offer会话开始")
          const offer = await that.peerConnA.createOffer()
          await that.onCreateOfferSuccess(offer)
        } catch (e) {
          console.log("创建会话描述SD失败：", e.toString())
        }
      }
      ,

      // 创建提议offer成功
      onCreateOfferSuccess: async function (event) {
        let that = this
        // 设置连接描述
        console.log("peerConnA 创建offer返回得SDP信息", event.sdp)
        console.log("设置peerConnA得本地描述start...")
        try {
          await that.peerConnA.setLocalDescription(event)
          console.log("设置peerConnA得本地描述成功")
        } catch (e) {
          console.log("设置peerConnA得本地描述错误：", e.toString())
        }

        console.log("设置peerConnB得远端描述 start")
        try {
          await that.peerConnB.setRemoteDescription(event)
          console.log("设置peerConnB得远端描述成功")

        } catch (e) {
          console.log("设置peerConnB得远端描述错误：", e.toString())
        }

        // 开始应答
        console.log("peerConnB创建应答 answer start")
        try {
          const answer = await that.peerConnB.createAnswer()
          console.log("peerConnB创建应答成功")
          await that.onCreateAnswerSuccess(answer)
        } catch (e) {
          console.log("peerConnB创建应答错误：", e.toString())
        }

      }
      ,

      // 创建answer应答成功
      onCreateAnswerSuccess: async function (answer) {
        let that = this
        console.log("peerConnB创建应答answer数据：", answer)
        console.log("peerConnA与peerConnB交换应答answer信息 start")

        try {
          await that.peerConnB.setLocalDescription(answer)
          console.log("设置peerConnB得本地answer 应答远端描述成功")

        } catch (e) {
          console.log("设置peerConnB得本地answer应答描述错误：", e.toString())
        }

        try {
          await that.peerConnA.setRemoteDescription(answer)
          console.log("设置peerConnA得远端answer应答描述成功")

        } catch (e) {
          console.log("设置peerConnA得远端answer应答描述错误：", e.toString())
        }
      }
      ,

      // 获取远端视频
      getRemoteStream: function (event) {
        let that = this
        console.log("获取远端视频数据如下：")
        console.log(event)
        if (that.remoteVideo.srcObject !== event.streams[0]) {
          that.remoteVideo.srcObject = event.streams[0]
          this.remoteVideo.play();
          console.log("开始获取远端视频流")
        }
      }
      ,
      // 监听ICE状态变化事件回调方法
      onIceStateChangeA: function (event) {
        console.log("监听 peerConnA ICE状态", this.peerConnA.iceConnectionState)
        console.log(event)
      }
      ,
      // 监听ICE状态变化事件回调方法
      onIceStateChangeB: async function (event) {
        console.log("监听 peerConnB ICE状态", this.peerConnB.iceConnectionState)
        console.log(event)
      }
      ,

      onIceCandidateA: async function (event) {
        let that = this

        try {
          if (event.candidate) {
            // 直接交换candidate数据，就不需要通过信令服务器传送
            await that.peerConnB.addIceCandidate(event.candidate)
            console.log("peerConnB IceCandidate----------")
            console.log(event)
            that.onAddIceCandidateSuccess(that.peerConnB)
          }
        } catch (e) {
          that.onAddIceCandidateError(that.peerConnB, e)
        }
        console.log("onIceCandidateA data:" + event.candidate)
      }
      ,
      onIceCandidateB: async function (event) {
        let that = this
        try {
          if (event.candidate) {
            await that.peerConnA.addIceCandidate(event.candidate)
            console.log("peerConnA IceCandidate----------")
            console.log(event)
            that.onAddIceCandidateSuccess(that.peerConnA)
          }
        } catch (e) {
          that.onAddIceCandidateError(that.peerConnA, e)
        }
        console.log("onIceCandidateB data:" + event.candidate)
      },
      //
      onAddIceCandidateSuccess: function (pc) {
        console.log("添加" + this.getPcName(pc) + "      IceCandidate 成功")
      },

      onAddIceCandidateError: function (pc, err) {
        console.log("添加" + this.getPcName(pc) + "       IceCandidate 失败" + err.toString())
      },
      getPcName: function (pc) {
        return (pc === this.peerConnA) ? "peerConnA" : "peerConnB"
      },
    }
    ,
    mounted: function () {
      this.localVideo = document.getElementById('localVideo');
      this.remoteVideo = document.getElementById('remoteVideo');
      this.myVideo = document.getElementById('myVideo');
    }
  })
</script>
</html>
